
#ifndef DBT_H_
#define DBT_H_

#include <assert.h>
#include <stddef.h>
#include <string.h>
#include <string>


//if db allocate a memory, it will set the flag. The caller need to release the
//memory
#define DBT_MALLOC 0x0001


//Dbt will not allocate or release memory. It is the responsibility of the caller to
//allocate or release memory. Dbt allows assignment operator and copy operation,
//the caller need to handle memory release.
class Dbt {

private:

    //the memory buffer
    char* m_data;

    //size of the memory buffer
    uint32_t m_size;

    //the size of the data in the memory buffer
    uint32_t m_datalen;

    //whether should free memory automatically
    uint32_t m_flag;

public:
    Dbt()
        : m_data(NULL), 
          m_size(0), 
          m_datalen(0), 
          m_flag(0) {
        }

    Dbt(char* d, uint32_t size, uint32_t datalen, uint32_t flag = 0) 
    : m_data(d), 
      m_size(size), 
      m_datalen(datalen), 
      m_flag(flag) { 
    }

    Dbt(const std::string& str) 
    : m_data((char*)str.data()), 
      m_size(str.size()), 
      m_datalen(str.size()), 
      m_flag(0) {
    }

    Dbt(const Dbt& dbt)
    : m_data(dbt.m_data), 
      m_size(dbt.m_size), 
      m_datalen(dbt.m_datalen), 
      m_flag(dbt.m_flag) {
    }

    ~Dbt() {
        clear();
    }

    void setBuffer(char* d, uint32_t size, uint32_t datalen, uint32_t flag = 0) {

        m_data = d; m_size = size; m_datalen = datalen; m_flag = flag;
    }

    // Return a pointer to the beginning of the referenced data
    char* data()  { return m_data; }

    // Return the length (in bytes) of memeory buffer
    uint32_t getSize()  { return m_size; }

    // Return the length (in bytes) of the referenced data
    uint32_t getDatalen()  { return m_datalen; }

    //set the data length
    void setDatalen(uint32_t len) { m_datalen = len; }

    void changeDatalen(int32_t len) { m_datalen += len; }

    //set the flag
    void setFlag(uint32_t flag) { m_flag |= flag;}

    //unset the flag
    void unsetFlag(uint32_t flag) { m_flag &= ~flag; }

    //get the flag
    uint32_t getFlag() {return m_flag;}

    // Change the dbt to refer to an empty array
    void clear() {
        m_data = NULL; m_size = 0; m_datalen = 0; 
    }

    bool empty() {
        return m_data == NULL;
    }

    char operator[](uint32_t i) {
        return m_data[i];
    }

    std::string toString() { return std::string(m_data, m_datalen); }


    Dbt& operator=(const Dbt& dbt){
        m_data = dbt.m_data;
        m_size = dbt.m_size;
        m_datalen = dbt.m_datalen;
        m_flag = dbt.m_flag;

        return *this;
    }


    Dbt& operator=(const std::string& str){
        m_data = (char*)str.data();
        m_size = str.size();
        m_datalen = m_size;
        m_flag = 0;

        return *this;
    }
};


#endif 
